# Greg Johnston
#  <greg.johnston@gmail.com>
#  wxview.py
#  The wxView class to manipulate our wxGlade-created XRC file

import wx
import wx.xrc as xrc
from wx.calendar import CalendarCtrl
from wx.lib.plot import PlotCanvas
from config import RitualConfig
from datetime import date
from calc import *

from entry import RitualEntry

class wxView(wx.App):
	"""This is the wxWindows GUI controller for Ritual"""
	def OnInit(self):
		self.Config = RitualConfig()

		self.Saved = True

		# Load all controls:
		self.res = xrc.XmlResource("ritual.xrc")
		self.Frame = self.res.LoadFrame(None, "top")

		self.Calendar = xrc.XRCCTRL(self.Frame, "calendar_ctrl_1")

		self.connect(None)

		self.SetTopWindow(self.Frame)
		self.Frame.Show(1)
	#	self.res.LoadDialog(self.Frame, "calculator").Show()

		return True

	def connect(self, handlers):
		"""Connects all the right handlers"""
		editor = self.res.LoadDialog(self.Frame, "editor")
		calculator = self.res.LoadDialog(self.Frame, "calculator")
		wx.EVT_MENU(self, wx.ID_EXIT, self.quit)
		wx.EVT_MENU(self, wx.ID_OPEN, lambda x: self.fileprompt("open"))
		wx.calendar.EVT_CALENDAR(self, self.Calendar.GetId(), lambda x: self.show_editor(RitualEntry("", 3, 0, 5025, "", "")))
		editor.Bind(wx.EVT_BUTTON, self.date_today, xrc.XRCCTRL(editor, "today"))
		# Central problem is that if we want stock buttons, they are referred to by ID and will
		# all have the same handler (i.e. the two wxID_ADD's have the same ID)
		# Other methods of binding don't seem to work?
		wx.EVT_BUTTON(self, xrc.XRCCTRL(editor, "today").GetId(), self.date_today)
#		wx.EVT_BUTTON(self, xrc.XRCCTRL(editor, "wxID_ADD").GetId(), self.time_calc_set)
#		wx.EVT_BUTTON(self, xrc.XRCCTRL(calculator, "wxID_ADD").GetId(), self.calc_add)
#		wx.EVT_BUTTON(self, xrc.XRCCTRL(calculator, "wxID_OK").GetId(), self.time_calc_okay)
#		wx.EVT_BUTTON(self, xrc.XRCCTRL(calculator, "wxID_CANCEL").GetId(), self.time_calc_cancel)

	def checksave(self):
		"""Checks to make sure you save when you're leaving a log"""
		if self.Saved == False:
			dialog = self.res.LoadDialog(self.Frame, "checksave")
			dialog.Bind(wx.EVT_BUTTON, lambda x: dialog.EndModal(wx.ID_SAVE), xrc.XRCCTRL(dialog, "wxID_SAVE"))
			dialog.Bind(wx.EVT_BUTTON, lambda x: dialog.EndModal(wx.ID_CANCEL), xrc.XRCCTRL(dialog, "wxID_CANCEL"))
			dialog.Bind(wx.EVT_BUTTON, lambda x: dialog.EndModal(wx.ID_CLOSE), xrc.XRCCTRL(dialog, "wxID_CLOSE"))
			response = dialog.ShowModal()
			dialog.Destroy()
			if response == wx.ID_SAVE: return "save"
			elif response == wx.ID_CANCEL: return "cancel"
			elif response == wx.ID_CLOSE: print "quit"
		else:
			return "quit"

	def quit(self, error=0):
		"""Quits the progam as wx needs it to, after making sure you save"""
		if self.checksave():
			self.Frame.Close(True)

	def title(self, file, extra=""):
		"""Gives the window its title"""
		if file and file != "": t = os.path.split(file)[1] + extra + " - Ritual"
		else: t = "Ritual"
		self.Frame.SetTitle(t)

	# Return Widget Values
	def get_value(self, widget):
		"""Returns the value of an editor widget, given its name"""
		editor = self.res.LoadDialog(self.Frame, "editor")
		if widget == "date": return xrc.XRCCTRL(editor, "dateentry").GetValue()
		elif widget == "course": return xrc.XRCCTRL(editor, "courseentry").GetValue()
		elif widget == "distance": return xrc.XRCCTRL(editor, "distanceentry").GetValue()
		elif widget == "distanceunit": return xrc.XRCCTRL(editor, "distanceunit").GetValue()
		elif widget == "time": return xrc.XRCCTRL(editor, "timeentry").GetValue()
		elif widget == "shoes": return xrc.XRCCTRL(editor, "shoesentry").GetValue()
		elif widget == "notes": return xrc.XRCCTRL(editor, "notesentry").GetValue()
		else: return None

	# I/O
	def fileprompt(self, type):
		"""Returns a filename; sets up a prompt call and calls it, given an action"""
		# Define our filters
		if type == "open" or type =="saveas":
			filter = "Ritual files (*.ritual)|*.ritual|"
		elif type == "convert":
			filter = "Coolrunning (downloadlog.cgi, *.csv)|downloadlog.cgi||*.csv|"
		# Give values for boxes
		if type == "open":
			filename = self.prompt("Open...", wx.FD_OPEN, filter)
		elif type == "convert":
			filename = self.prompt("Import...", wx.FD_OPEN, filter)
		elif type == "saveas":
			filename = self.prompt("Save as...", wx.FD_OVERWRITE_PROMPT, filter)
		return filename


	def prompt(self, title, style, filter):
		"""Returns a filename, given a title, filter, and GTK stock button"""
		dialog = wx.FileDialog(self.Frame, message=title, wildcard=filter, style=style)
		if dialog.ShowModal() == wx.ID_OK:
			filename = dialog.GetPath()
		else:
			filename = True
		dialog.Destroy()
		print filename
		return filename

	def set_saved(self, status, file):
		"""Sets the saved-status to True or False"""
		if status == True:
			self.title(file)
			self.Saved = True
		else:
			self.title(file, " *")
			self.Saved = False

	# Calendar
	def calendar_mark_month(self, log=None):
		"""Marks all the days in the selected month which have runs in the passed log"""
		chosen_month = self.Calendar.GetDate().GetMonth()+1 # returns month as 0-11
		chosen_year = self.Calendar.GetDate().GetYear()
		for date_tuple in log.log.keys():
			date = date_tuple[0]
			if date.month == chosen_month and date.year == chosen_year:
				self.Calendar.SetHoliday(date.day)

	def calendar_to_month_year(self, date):
		"""Moves the calendar to the month and year it is passed"""
		self.Calendar.year = date.year
		self.Calendar.month = date.month

	def calendar_selected_date_string(self):
		"""Returns the date selected by the calendar as a MM/DD/YYYY string"""
		return self.Calendar.GetDate().FormatDate()

	def calendar_selected_date(self):
		"""Returns the date selected by the calendar as a datetime.date"""
		cdate = self.Calendar.GetDate()
		# make sure we add 1 to the month is because it gives months 0-11
		return date(cdate.GetYear(), cdate.GetMonth()+1, cdate.GetDay()) # we want to make (year, month, day) 

	# Editor
	def show_editor(self, run):
		"""Shows the Editor window"""
		editor = self.res.LoadDialog(self.Frame, "editor")
		xrc.XRCCTRL(editor, "dateentry").SetValue(self.calendar_selected_date_string())
		xrc.XRCCTRL(editor, "courseentry").SetValue(run.course)
		xrc.XRCCTRL(editor, "shoesentry").SetValue(run.shoes)
		xrc.XRCCTRL(editor, "distanceentry").SetValue(str(run.distance))
		xrc.XRCCTRL(editor, "distanceunit").SetStringSelection(code_unit(run.unit))
		xrc.XRCCTRL(editor, "timeentry").SetValue(seconds_timestr(run.time))
		xrc.XRCCTRL(editor, "notesentry").SetValue(run.notes)
		self.update_pace()
		editor.ShowModal()

	def date_today(self, widget):
		"""Sets the value of the date field to today's date"""
		# Doesn't work. Not sure why.
		print "date_today"
		editor = self.res.LoadDialog(self.Frame, "editor")
		entry = xrc.XRCCTRL(editor, "dateentry")
		entry.SetValue(date.today().strftime("%m/%d/%Y"))

	def update_pace(self, widget=None, signal=None):
		"""Updates the pace label value to read the pace, based on distance/time"""
		# Also doesn't work. Problem updating widgets?
		editor = self.res.LoadDialog(self.Frame, "editor")
		tstr = xrc.XRCCTRL(editor, "timeentry").GetValue()
		unit = xrc.XRCCTRL(editor, "distanceunit").GetCurrentSelection()
		try:
			distance = float(xrc.XRCCTRL(editor, "distanceunit").GetValue())
			xrc.XRCCTRL(editor, "pacevalue").SetLabel(calc_pace(tstr, distance, unit))
		except:
			return 0

	def set_combos(self, log):
		"""Sets up the two ComboBox's, given a log"""
		editor = self.res.LoadDialog(self.Frame, "editor")
		xrc.XRCCTRL(editor, "courseentry").Clear()
		xrc.XRCCTRL(editor, "shoesentry").Clear()
		self.set_courses_combo(log.courses, xrc.XRCCTRL(editor, "courseentry"))
		self.set_shoes_combo(log, xrc.XRCCTRL(editor, "shoesentry"))

	def set_courses_combo(self, courses, combobox):
		"""Sets up the courseentry ComboBox"""
		for course in sorted(courses.keys()):
			combobox.AppendItems([course])

	def set_shoes_combo(self, log, combobox):
		"""Sets up the shoesentry ComboBox"""
		for date in log.log:
			entry = log.log[date]
			combobox.AppendItems([entry])

	def set_distance_from_course(self, courses):
		"""Sets the distance and unit entries based on the course entry"""
		editor = self.res.LoadDialog(self.Frame, "editor")
		course = xrc.XRCCTRL(editor, "courseentry").GetValue()
		if course in courses:
			xrc.XRCCTRL(editor, "distanceentry").SetValue(courses[course][0])
			xrc.XRCCTRL(editor, "distanceunit").SetStringSelection(code_unit(courses[course][1]))

	def hide_editor(self, widget=None):
		"""Hides the Editor dialog"""
		self.res.LoadDialog(self.Frame, "editor").Hide()

	# Calculator
	def calc_add(self, button):
		"""Adds a row to the calculator"""
		print "calc_add"
		dialog = self.res.LoadDialog(self.Frame, "calculator")
		grid = xrc.XRCCTRL(dialog, "calcentry1").GetContainingSizer()
		grid.SetRows(grid.GetRows()+1)
		grid.Add(wx.TextCtrl(dialog, value="HH:MM:SS"))
		dialog.Update()

	def time_calc(self, widget):
		"""Returns a total time after popping up a calculator"""
		print "time_calc"
		self.res.LoadDialog(self.Frame, "calculator").ShowModal()

	def time_calc_okay(self):
		"""Called when user presses 'Okay' button on calculator"""
		print "time_calc_okay"
		dialog = self.res.LoadDialog(self.Frame, "calculator")
		for child in dialog.GetChildren():
			try:
				times += [child.GetValue()]
			except:
				pass
		dialog.Hide()
		return add_times(times)

	def time_calc_cancel(self):
		"""Called when user presses 'Cancel' button on calculator"""
		print "time_calc_cancel"
		self.res.LoadDialog(self.Frame, "calculator").Hide()
		return "HH:MM:SS"

	def time_calc_set(self, widget):
		"""Sets the timeentry to the calculator's return"""
		print "time_calc_set"
		editor = self.res.LoadDialog(self.Frame, "editor")
		xrc.XRCCTRL(editor, "timeentry").SetValue(self.time_calc(widget))
		editor.Update()

if __name__ == '__main__':
	app = wxView()
	app.MainLoop()
